/*
 * =====================================================================================
 *
 *       Filename:  findByKill.c
 *
 *    Description:  Vyhleda procesy podezrele ze skryti. 
 *                  Zjisti jake procesy jsou zobrazeny v /proc, pote
 *                  vsem procesum (1 az MAX_PID) zasle signal. Pokud
 *                  proces prijme signal ale nebyl nalezen v /proc, je 
 *                  podezrely ze skryti.
 *                  PID podezrelych procesu jsou vypsana na stdout.
 *
 *        Version:  1.0
 *        Created:  2013
 *       Compiler:  gcc
 *
 *         Author:  Radek Necas, xnecas18@stud.fit.vutbr.cz 
 *   Organization:  FIT, VUT
 *
 * =====================================================================================
 */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>



#define MAX_PID_PATH "/proc/sys/kernel/pid_max"
#define MAX_PID_DEFAULT 32768

/**
 * Funkce pro ziskani maximalni hodnoty PID.
 * Cte jej ze souboru /proc/sys/kernel/pid_max.
 *
 * @return maximalni dostupne pid na pocitaci, nebo implicitni hodnotu 32768 (pokud nelze cist ze souboru).
 */
long int getMaxPid() {
    long int maxpid = MAX_PID_DEFAULT;
    char maxPidStr[8];
    FILE *fpid = fopen(MAX_PID_PATH, "r");
    if(fpid != NULL) {
        if(fgets(maxPidStr, 8, fpid) != NULL) {
            maxpid = atof(maxPidStr);
            if(maxpid == 0)
                maxpid = MAX_PID_DEFAULT;
        }
    }

    return maxpid;
}

/**
 * Funkce vyhleda skryte procesy, respektive procesy, ktere jsou podezrele
 * ze skryti a vypise jejich PID na stdout.
 *
 * Z /proc zjisti, ktere procesy jsou pro uzivatele viditelne a ulozi je do pole.
 * Pote zasle na vsechny mozne pid signal SIGCONT. Pokud nejaky proces signal prijme 
 * a neni ve zjistenem poli nebo neodpovida na systemove volani getdents
 * je vyhodnocen jako podezrely ze skryti.
 *
 * @return pocet podezrelych procesu
 */
int findByKill() {
    struct dirent *de = NULL;
    DIR *dh = NULL;

    char procs[MAX_PID_DEFAULT + 1];
    memset(procs, 0, sizeof(procs));

    if((dh = opendir("/proc")) == NULL) {
        fprintf(stderr, "Nepodarilo se otevrit /proc\n");
        return 0;
    }

    // Ulozim si pid nalezena v /proc
    int actPid;
    while((de = readdir(dh)) != NULL) {
        actPid = atoi(de->d_name);
        if(actPid > 0 && actPid <= MAX_PID_DEFAULT) {
            procs[actPid] = 1;
        }
    }
    closedir(dh);
    
    if((dh = opendir("/proc")) == NULL) {
        fprintf(stderr, "Nepodarilo se otevrit /proc\n");
        return 0;
    }
/*
    // Ulozim si pid nalezena v /proc
    char procs2[MAX_PID_DEFAULT + 1];
    memset(procs2, 0, sizeof(procs));
    while((de = readdir(dh)) != NULL) {
        actPid = atoi(de->d_name);
        if(actPid > 0 && actPid <= MAX_PID_DEFAULT) {
            procs2[actPid] = 1;
        }
    }
    closedir(dh);

    for(int i = 0; i <= MAX_PID_DEFAULT; i++) {
        if(procs[i] != procs2[i]) {
            printf("Proces s pid %d neni v obou seznamech\n", i);
        }
    }
    int suspicious = 0;
*/

    char path[32];
    struct stat st;
    int suspicious = 0;
    for(int i = 1; i <= MAX_PID_DEFAULT; i++) {     // Zaslani signalu na vsechna pid
        if(kill(i, SIGCONT) == 0) {     // Proces signal prijal
            memset(path, 0, sizeof(path));
            snprintf(path, sizeof(path), "/proc/%d", i);

            //if(stat(path, &st) || procs[i] == 0) {
            if(stat(path, &st) < 0) {
                //  Proces signal prijal, ale nenasel se pro nej zazna v /proc
                //  nebo selze volani stat() - vola syscall getdents()
                printf("Process s PID = %d muze byt skryty\n", i);
                suspicious++;
            }
        }
    }

    return suspicious;
}


